package com.swak.fx.support.ui;

import java.util.List;

import org.controlsfx.glyphfont.FontAwesome;

import com.swak.fx.support.animation.AnimationFX;
import com.swak.utils.StringUtils;

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.css.CssMetaData;
import javafx.css.SimpleStyleableObjectProperty;
import javafx.css.Styleable;
import javafx.css.StyleableObjectProperty;
import javafx.css.StyleablePropertyFactory;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.Button;
import javafx.scene.control.Skin;
import javafx.scene.control.skin.ButtonSkin;
import javafx.scene.input.MouseEvent;
import javafx.scene.shape.Circle;

/**
 * 自定义 Button
 * 
 * @author 618lf
 */
public class UIButton extends Button implements UILifecycle {

	// ================================================================================
	// Properties
	// ================================================================================
	private static final StyleablePropertyFactory<UIButton> FACTORY = new StyleablePropertyFactory<>(
			Button.getClassCssMetaData());
	private static final String STYLE_CLASS = "ui-button";
	private static final String DEFAULT_STYLE_CLASS = "ui-button-default";
	private static final String INVERSE_STYLE_CLASS = "ui-button-inverse";
	private static final String PRIMARY_STYLE_CLASS = "ui-button-primary";
	private static final String SUCCESS_STYLE_CLASS = "ui-button-success";
	private static final String INFO_STYLE_CLASS = "ui-button-info";
	private static final String WARNING_STYLE_CLASS = "ui-button-warning";
	private static final String DANGER_STYLE_CLASS = "ui-button-danger";
	private static final String PLAIN_STYLE_CLASS = "ui-button-plain";
	private static final String STYLESHEET = UI.load("css/UIButton.css");

	private final StringProperty typeProperty = new SimpleStringProperty(DEFAULT_STYLE_CLASS);
	private AnimationFX animation;

	public UIButton() {
		super();
		this.init();
	}

	public UIButton(String name) {
		super(name);
		this.init();
	}

	public UIButton(FontAwesome.Glyph icon) {
		super();
		this.setGraphic(new UIIcon(icon));
		this.init();
	}

	public UIButton(String name, FontAwesome.Glyph icon) {
		super(name, new UIIcon(icon));
		this.init();
	}

	@Override
	public void initializeParts() {
		getStyleClass().setAll(STYLE_CLASS);
		getStyleClass().add(DEFAULT_STYLE_CLASS);
		setAlignment(Pos.CENTER);
		this.setPrefSize(100, 40);
	}

	@Override
	public void layoutParts() {

		UIIcon icon = null;
		Node graphic = this.getGraphic();
		if (graphic != null && graphic instanceof UIIcon) {
			icon = (UIIcon) graphic;
		}

		// 修改图标的样式
		if (icon != null) {
			switch (typeProperty.get()) {
			case DEFAULT_STYLE_CLASS: {
				icon.Font();
				break;
			}
			default: {
				icon.White();
				break;
			}
			}
		}
	}

	@Override
	public void setupEventHandlers() {
		this.setEventHandler(MouseEvent.MOUSE_CLICKED, (e) -> {
			if (this.animation != null) {
				this.animation.play();
			}
		});
	}

	@Override
	public void setupValueChangedListeners() {
		typeProperty.addListener(this::onChangeStyleClass);
		shadowProperty.addListener((ob, o, n) -> {
			if (n != null) {
				this.setEffect(n.shadowOf());
				this.setPickOnBounds(false);
			} else {
				this.setEffect(null);
				this.setPickOnBounds(true);
			}
		});
		graphicProperty().addListener((ob, o, n) -> {
			this.layoutParts();
		});
		disabledProperty().addListener((ob, o, n) -> {
			this.setOpacity(n ? 0.3 : 1);
		});
		animationProperty().addListener((ob, o, n) -> {
			if (n != null) {
				this.animation = n.New();
				this.animation.setNode(this);
			}
		});
	}

	private void onChangeStyleClass(ObservableValue<? extends String> ob, String oldValue, String newValue) {
		if (StringUtils.isNotBlank(oldValue)) {
			getStyleClass().remove(oldValue);
		}
		if (StringUtils.isNotBlank(newValue)) {
			getStyleClass().add(newValue);
		}
		this.layoutParts();
	}

	public UIButton Icon(FontAwesome.Glyph icon) {
		this.setGraphic(new UIIcon(icon));
		return this;
	}

	public UIButton Default() {
		this.typeProperty.set(DEFAULT_STYLE_CLASS);
		return this;
	}

	public UIButton Inverse() {
		this.typeProperty.set(INVERSE_STYLE_CLASS);
		return this;
	}

	public UIButton Primary() {
		this.typeProperty.set(PRIMARY_STYLE_CLASS);
		return this;
	}

	public UIButton Success() {
		this.typeProperty.set(SUCCESS_STYLE_CLASS);
		return this;
	}

	public UIButton Info() {
		this.typeProperty.set(INFO_STYLE_CLASS);
		return this;
	}

	public UIButton Warning() {
		this.typeProperty.set(WARNING_STYLE_CLASS);
		return this;
	}

	public UIButton Danger() {
		this.typeProperty.set(DANGER_STYLE_CLASS);
		return this;
	}

	public UIButton Plain() {
		this.typeProperty.set(PLAIN_STYLE_CLASS);
		return this;
	}

	public UIButton Disable() {
		this.setDisable(!this.isDisable());
		return this;
	}

	public UIButton Round() {
		double round = this.getPrefHeight() / 2;
		this.setPrefSize(this.getPrefHeight(), this.getPrefHeight());
		Circle circle = new Circle();
		circle.setRadius(round);
		circle.setCenterX(round);
		circle.setCenterY(round);
		this.setClip(circle);
		return this;
	}

	// ================================================================================
	// Styleable Properties
	// ================================================================================
	private final StyleableObjectProperty<UI.Shadows> shadowProperty = new SimpleStyleableObjectProperty<>(
			StyleableProperties.SHADOW, this, "shadow", UI.Shadows.LEVEL0);

	public StyleableObjectProperty<UI.Shadows> shadowProperty() {
		return shadowProperty;
	}

	public UIButton Shadow(UI.Shadows shadow) {
		this.shadowProperty.set(shadow);
		return this;
	}

	public UIButton Shadow() {
		this.shadowProperty.set(null);
		return this;
	}

	private final ObjectProperty<UI.Animations> animationProperty = new SimpleObjectProperty<>();

	public ObjectProperty<UI.Animations> animationProperty() {
		return animationProperty;
	}

	public UIButton Animation(UI.Animations animation) {
		this.animationProperty.set(animation);
		return this;
	}

	// ================================================================================
	// CSSMetaData
	// ================================================================================

	private static class StyleableProperties {

		private static final List<CssMetaData<? extends Styleable, ?>> cssMetaDataList;

		private static final CssMetaData<UIButton, UI.Shadows> SHADOW = FACTORY.createEnumCssMetaData(UI.Shadows.class,
				"-ui-shadow", UIButton::shadowProperty, UI.Shadows.LEVEL0);

		static {
			cssMetaDataList = UILifecycle.cssMetaDataList(Button.getClassCssMetaData(), SHADOW);
		}
	}

	public static List<CssMetaData<? extends Styleable, ?>> getControlCssMetaDataList() {
		return StyleableProperties.cssMetaDataList;
	}

	// ================================================================================
	// Override Methods
	// ================================================================================
	@Override
	protected Skin<?> createDefaultSkin() {
		return new UIButtonSkin(this);
	}

	@Override
	public List<CssMetaData<? extends Styleable, ?>> getControlCssMetaData() {
		return UIButton.getControlCssMetaDataList();
	}

	@Override
	public String getUserAgentStylesheet() {
		return STYLESHEET;
	}

	// ================================================================================
	// Skin
	// ================================================================================

	static class UIButtonSkin extends ButtonSkin {
		public UIButtonSkin(UIButton button) {
			super(button);
		}
	}

	// ================================================================================
	// Static Methods
	// ================================================================================

	public static UIButton Default(String name, FontAwesome.Glyph icon) {
		return new UIButton(name, icon);
	}

	public static UIButton Primary(String name, FontAwesome.Glyph icon) {
		return new UIButton(name, icon).Primary();
	}

	public static UIButton Success(String name, FontAwesome.Glyph icon) {
		return new UIButton(name, icon).Success();
	}

	public static UIButton Info(String name, FontAwesome.Glyph icon) {
		return new UIButton(name, icon).Info();
	}

	public static UIButton Warning(String name, FontAwesome.Glyph icon) {
		return new UIButton(name, icon).Warning();
	}

	public static UIButton Danger(String name, FontAwesome.Glyph icon) {
		return new UIButton(name, icon).Danger();
	}

	public static UIButton Plain(String name, FontAwesome.Glyph icon) {
		return new UIButton(name, icon).Plain();
	}
}